package com.ruoyi.data.tdengine.service;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ruoyi.common.annotation.DataSource;
import com.ruoyi.common.enums.DataSourceType;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.data.tdengine.domain.AvgForTimeInterval;
import com.ruoyi.data.tdengine.domain.Sensor;
import com.ruoyi.data.tdengine.domain.SensorDataOfEquipment;
import com.ruoyi.data.tdengine.domain.ValueAvg;
import com.ruoyi.data.tdengine.mapper.SensorMapper;
import com.ruoyi.data.tdengine.utils.CurlUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Created by james-YU on 2020/12/22
 * DESC:
 */
@Service
@DataSource(DataSourceType.TDENGINE)
@Slf4j
public class SensorService {

    @Autowired
    private SensorMapper sensorMapper;

    /**
     * 新增传感器的时候，根据传感器的code去判断是否存在，若不存在，则调用创建子表逻辑，如果该子表存在，那么就直接drop掉
     * @param sensor
     * @return
     */
    public int insert(Sensor sensor) {
        if (sensor == null) {
            return -1;
        }
        Map<String, Object> map = new HashMap<>();
        return sensorMapper.save(sensor);
       // return saveRestful(sensor);
    }




    /**
     * 新增传感器的时候，根据传感器的code去判断是否存在，若不存在，则调用创建子表逻辑，如果该子表存在，那么就直接drop掉
     * @param data
     * @return
     */
    public int insertBatch(List<Sensor> data) {
        if (data == null || data.size() == 0) {
            return -1;
        }
        int row = 0;
        try{
            //row = saveBatchRestful(data);
            row = sensorMapper.saveBatch(data);
        }catch (Exception e){
            e.printStackTrace();
            //如果批量插入不成功 则单独插入

            for (Sensor sensor:data){
                try {
                    //row += saveRestful(sensor);
                    row += sensorMapper.save(sensor);
                }catch (Exception e1){
                    e1.printStackTrace();
                }
            }
        }

        return row;
    }


    // 新增传感器，需要新增传感器超级表下面的子表
    public int addSensor(Sensor sensor) {
        // 删除该传感器子表
        if (sensor == null) {
            return -1;
        }
        if (!"".equals(sensor.getSensorCode()) && sensor.getSensorCode() != null) {
            // 删除原表
            dropTable(sensor.getSensorCode());
            // 创建新表
            if (!"".equals(sensor.getEquipmentCode()) && sensor.getEquipmentCode() != null) {
                createSensorTable(sensor);
            }
        }
        return 1;


    }


    public List<Sensor> listAll() {
        //return listAllRestful();
        return sensorMapper.listAll();
    }

    /**
     * 查询指定传感器执行时间跨度的数据，按指定分钟数为间隔 查询在指定的时间间隔内的传感器的温度的平均值
     */
    public List<ValueAvg> getAvgForTimeInterval(AvgForTimeInterval avgForTimeInterval) {
        if (avgForTimeInterval == null) {
            return new ArrayList<>();
        }
        // 对时间跨度做处理
        String sections = "now-"+avgForTimeInterval.getSection()+"h";
        String intervals = avgForTimeInterval.getInterval() + "m";
        avgForTimeInterval.setSection(sections);
        avgForTimeInterval.setInterval(intervals);
        //return getAvgForTimeIntervalRestful(avgForTimeInterval);
        return sensorMapper.getAvgForTimeInterval(avgForTimeInterval);
    }





    /**
     * 判断传感器code 是否存在
     * 若为true：代表已存在
     * 若为false： 代表不存在
     */
    public boolean checkSensorCodeIsExist(String sensorCode) {
        if (sensorCode != null && !"".equals(sensorCode)) {
            //return findSensorCodeRestful(sensorCode) > 0;
            return sensorMapper.findSensorCode(sensorCode) > 0;
        }
        return false;
    }

    public void dropTable(String sensorCode) {
        //dropOldSensorRestful(sensorCode);
        sensorMapper.dropOldSensor(sensorCode);
    }

    public void createSensorTable(Sensor sensor) {
        Map<String, Object> map = new HashMap<>();
        // 默认的数据库
        map.put("dbname","iot_eos_v1");
        // 默认的超级表
        map.put("stable","sensor");
        // 默认的传感器数据，tag的值也在其中，tag就是设备code
        map.put("values",sensor);
        // 创建sensor子表
        //createTableRestful(map);
        sensorMapper.createTable(map);
    }

    // 查询指定设备下的指定时间区间的传感器的数据
    public List<Sensor> findSensorDataOfEquipment(SensorDataOfEquipment sensorDataOfEquipment) {
        long startTime = System.currentTimeMillis();
        String sections = "now-"+sensorDataOfEquipment.getSection()+"h";
        sensorDataOfEquipment.setSection(sections);

        List<Sensor> sensors = findSensorDataOfEquipmentRestful(sensorDataOfEquipment);
        long endTime = System.currentTimeMillis();
        System.out.println("程序运行时间：" + (endTime - startTime) + "ms");
        //return sensors;
        return sensorMapper.findSensorDataOfEquipment(sensorDataOfEquipment);
    }

    // 查询指定设备下所有传感器的最新的数据
    public Sensor findLastSensorData(SensorDataOfEquipment sensorDataOfEquipment) {
        //return findLastSensorDataRestful(sensorDataOfEquipment);
        return sensorMapper.findLastSensorData(sensorDataOfEquipment);
    }

    // 获取指定设备下的传感器在指定时间内的平均值
    public Double getAvgForTimeLimit(SensorDataOfEquipment sensorDataOfEquipment) {
        String sections = "now-"+sensorDataOfEquipment.getSection()+"s";
        //return getAvgForTimeLimitRestful(sensorDataOfEquipment);
        return sensorMapper.getAvgForTimeLimit(sensorDataOfEquipment);
    }


    public  List<Sensor> findTimeDataCount(String sensorCode) {
       // return findTimeDataRestful(sensorCode);
        return sensorMapper.findTimeData(sensorCode);
    }

    public List<Sensor> getChart(Date planBeginTime, Date planEndTime, String sensorCode) {
        if (planBeginTime==null && planEndTime !=null){
            //return getChartAndPlanEndTimeRestful(planEndTime,sensorCode);
            return sensorMapper.getChartAndplanEndTime(planEndTime,sensorCode);
        }else if (planEndTime==null && planBeginTime!= null){
            //return getChartAndPlanBeginTimeRestful(planBeginTime,sensorCode);
            return sensorMapper.getChartAndPlanBeginTime(planBeginTime,sensorCode);
        }else {
            //return getChartRestful(planBeginTime,planEndTime,sensorCode);
            return sensorMapper.getChart(planBeginTime,planEndTime,sensorCode);
        }
    }

    public List<Sensor> getChartByHour(Date planBeginTime, Date planEndTime, String sensorCode) {
        //return getChartByHourRestful(planBeginTime,planEndTime,sensorCode);
          return sensorMapper.getChartByHour(planBeginTime,planEndTime,sensorCode);
    }

    public List<Sensor> getChartMinute(Date planBeginTime, Date planEndTime, String sensorCode) {
        //return getChartMinuteRestful(planBeginTime,planEndTime,sensorCode);
        return sensorMapper.getChartMinute(planBeginTime,planEndTime,sensorCode);
    }

    public List<Sensor> findAll(){
        return sensorMapper.findAll();
    }

    public Sensor findSensorData(String sensorCode, Double warnThreshold, int timeInterval) {
        return sensorMapper.findSensorData(sensorCode,warnThreshold,timeInterval);
        //return findSensorDataRestful(sensorCode,warnThreshold,timeInterval);
    }

    public void insertSensorData(String sensorCode, Double data, String equipmentCode) {
        //insertSensorDataRestful(sensorCode,data,equipmentCode);
        sensorMapper.insertSensorData(sensorCode, data);
    }

    public List<Sensor> selectSensorData(String sensorCode) {
        //return selectSensorDataRestful(sensorCode);
        return sensorMapper.selectSensorData(sensorCode);
    }

    public void insertSensorBatchData(String sensorCode, double random, int i, String equipmentCode) {
        sensorMapper.insertSensorBatchData(sensorCode,random,i);
        //insertSensorBatchDataRestful(sensorCode,random,i,equipmentCode);
    }

    public List<String> selectSensorTest() {
        return sensorMapper.selectSensorTest();
    }


    /**
     * restful 风格
     */
    private int saveRestful(Sensor sensor){
        String sql = "INSERT INTO iot_eos_v1."+sensor.getSensorCode()+" (ts, sensor_code, value) values (\'"+sensor.getTs()+"\',\'"+sensor.getSensorCode()+"\',\'"+sensor.getValue()+"\')";
        JSONObject jsonObject = CurlUtils.sendRestFulSql(sql);
        return Integer.parseInt((String) jsonObject.get("rows"));
    }

    private int saveBatchRestful(List<Sensor> data){
        data.stream().peek(this::saveRestful).collect(Collectors.toList());
        return 1;
    }

    private void createTableRestful(Map<String, Object> map){
        Sensor sensor = (Sensor) map.get("values");
        String sql = "create table IF NOT EXISTS iot_eos_v1."+sensor.getSensorCode()+" using iot_eos_v1.sensor  tags(\'"+sensor.getEquipmentCode()+"\')";
        CurlUtils.sendRestFulSql(sql);
    }

    private  List<Sensor> listAllRestful(){
        String sql = "select ts, sensor_code, value,equipment_code from iot_eos_v1.sensor";
        return selectSensor(CurlUtils.sendRestFulSql(sql));
    }

    private List<ValueAvg> getAvgForTimeIntervalRestful(AvgForTimeInterval avgForTimeInterval){
        String sql = "select avg(value) as value from iot_eos_v1."+avgForTimeInterval.getSensorCode()+"" +
                "  where ts >= "+avgForTimeInterval.getSection()+" interval("+avgForTimeInterval.getInterval()+")";
        JSONObject jsonObject = CurlUtils.sendRestFulSql(sql);
        return selectValueAvg(jsonObject);
    }



    private int findSensorCodeRestful(String sensorCode){
        String sql = "select count(*) from iot_eos_v1.sensor where sensor_code = \'"+sensorCode+"\'";
        JSONObject jsonObject = CurlUtils.sendRestFulSql(sql);
        return Integer.parseInt(jsonObject.getString("rows"));
    }

    private void dropOldSensorRestful(String sensorCode){
        String sql = " DROP TABLE IF EXISTS iot_eos_v1."+sensorCode;
        CurlUtils.sendRestFulSql(sql);
    }

    private List<Sensor> findSensorDataOfEquipmentRestful(SensorDataOfEquipment sensorDataOfEquipment){
        String sql = "select ts, sensor_code, value, equipment_code from iot_eos_v1.sensor";
        if (StringUtils.isNotEmpty(sensorDataOfEquipment.getSection()))
            sql += " where ts >= "+sensorDataOfEquipment.getSection()+"";
        if (StringUtils.isNotEmpty(sensorDataOfEquipment.getEquipmentCode()))
            sql += " and equipment_code=\'"+sensorDataOfEquipment.getEquipmentCode()+"\'";
        if (StringUtils.isNotEmpty(sensorDataOfEquipment.getSensorCode()))
            sql += " and sensor_code=\'"+sensorDataOfEquipment.getSensorCode()+"\'";
        JSONObject jsonObject = CurlUtils.sendRestFulSql(sql);
        return selectSensor(jsonObject);
    }


    private Sensor findLastSensorDataRestful(SensorDataOfEquipment sensorDataOfEquipment){
        String sql = "select last(ts) as ts, last(sensor_code) as sensor_code, last(value) as value from iot_eos_v1.sensor";
        if (StringUtils.isNotEmpty(sensorDataOfEquipment.getSensorCode()))
            sql += " where sensor_code="+sensorDataOfEquipment.getSensorCode();
        if (StringUtils.isNotEmpty(sensorDataOfEquipment.getEquipmentCode()))
            sql += "  and equipment_code="+sensorDataOfEquipment.getEquipmentCode();
        JSONObject jsonObject = CurlUtils.sendRestFulSql(sql);
        List<Sensor> sensorList = selectSensor(jsonObject);
        if (sensorList.isEmpty())return null;
        else return sensorList.get(0);
    }

    private Double getAvgForTimeLimitRestful(SensorDataOfEquipment sensorDataOfEquipment){
        String sql = " select avg(value) as value from iot_eos_v1.sensor";
        if (StringUtils.isNotEmpty(sensorDataOfEquipment.getSection()))
            sql += " where ts >= "+sensorDataOfEquipment.getSection();
        if (StringUtils.isNotEmpty(sensorDataOfEquipment.getSensorCode()))
            sql += " and sensor_code="+sensorDataOfEquipment.getSensorCode();
        if (StringUtils.isNotEmpty(sensorDataOfEquipment.getEquipmentCode()))
            sql += " and equipment_code="+sensorDataOfEquipment.getEquipmentCode();
        JSONObject jsonObject = CurlUtils.sendRestFulSql(sql);
        String data = jsonObject.getString("data");
        data = data.replace("[","");
        data = data.replace("]","");
        if (StringUtils.isNotEmpty(data))return Double.valueOf(data);
        else return null;
    }

    private List<Sensor> findTimeDataRestful(String sensorCode){
        String sql = "select avg(value) as value from iot_eos_v1."+sensorCode+"  where ts>=now-30d INTERVAL(1d);";
        JSONObject jsonObject = CurlUtils.sendRestFulSql(sql);
        return selectChart(jsonObject);
    }



    private List<Sensor> getChartAndPlanEndTimeRestful(Date planEndTime, String sensorCode){
        String endTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(planEndTime);
        String sql = "select avg(value) as value from  iot_eos_v1."+sensorCode+" where  ts<=\'"+endTime+"\' INTERVAL(1d);";
        JSONObject jsonObject = CurlUtils.sendRestFulSql(sql);
        return selectChart(jsonObject);
    }


    private List<Sensor> getChartAndPlanBeginTimeRestful(Date planBeginTime, String sensorCode){
        String beginTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(planBeginTime);
        String sql = "select avg(value) as value from iot_eos_v1."+sensorCode+" where ts>=\'"+beginTime+"\'  INTERVAL(1d);";
        return selectChart(CurlUtils.sendRestFulSql(sql));
    }

    private List<Sensor> getChartRestful(Date planBeginTime, Date planEndTime, String sensorCode){
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String beginTime = simpleDateFormat.format(planBeginTime);
        String endTime = simpleDateFormat.format(planEndTime);
        String sql = "select avg(value) as value from iot_eos_v1."+sensorCode+" where ts>=\'"+beginTime+"\' and ts<=\'"+endTime+"\' INTERVAL(1d);";
        return selectChart(CurlUtils.sendRestFulSql(sql));
    }

    private  List<Sensor> getChartByHourRestful(Date planBeginTime, Date planEndTime, String sensorCode){
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String beginTime = simpleDateFormat.format(planBeginTime);
        String endTime = simpleDateFormat.format(planEndTime);
        String sql = "select avg(value) as value from iot_eos_v1."+sensorCode+" where ts>=\'"+beginTime+"\' and ts<=\'"+endTime+"\'  INTERVAL(1h);";
        return selectChart(CurlUtils.sendRestFulSql(sql));
    }

    private List<Sensor> getChartMinuteRestful(Date planBeginTime, Date planEndTime, String sensorCode){
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String beginTime = simpleDateFormat.format(planBeginTime);
        String endTime = simpleDateFormat.format(planEndTime);
        String sql = "select avg(value) as value from iot_eos_v1."+sensorCode+" where ts>=\'"+beginTime+"\' and ts<=\'"+endTime+"\'  INTERVAL(5m);";
        return selectChart(CurlUtils.sendRestFulSql(sql));
    }

    private Sensor findSensorDataRestful(String sensorCode, Double warnThreshold, int timeInterval){
        String sql = "select  last(ts) as ts, last(sensor_code) as sensor_code, avg(value) as value from iot_eos_v1."+sensorCode+" where value>="+warnThreshold+" and ts >=now-"+timeInterval+"m limit 1";
        JSONObject jsonObject = CurlUtils.sendRestFulSql(sql);
        String data = jsonObject.getString("data");
        data = data.replace("[","");
        data = data.replace("]","");
        data = data.replace("\"", "");
        if (StringUtils.isEmpty(data))return null;
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
        Sensor sensor = new Sensor();
        String[] split = data.split(",");
        try {
            sensor.setTs(new Timestamp(simpleDateFormat.parse(split[0]).getTime()));
        } catch (ParseException e) {
            log.error("error:{}",e.getMessage());
        }
        sensor.setSensorCode(split[1]);
        sensor.setValue(Double.valueOf(split[2]));
        return sensor;
    }

    private void insertSensorDataRestful(String sensorCode, Double value, String equipmentCode){
        String sql = "insert into iot_eos_v1."+sensorCode+" using iot_eos_v1.sensor tags("+equipmentCode+") values(now,\'"+sensorCode+"\',"+value+");";
        CurlUtils.sendRestFulSql(sql);
    }

    private  List<Sensor> selectSensorDataRestful(String sensorCode){
        String sql = "select * from "+sensorCode;
        return selectSensor(CurlUtils.sendRestFulSql(sql));
    }

    private void insertSensorBatchDataRestful(String sensorCode, double value, int time, String equipmentCode){
        String sql = "insert into  iot_eos_v1."+sensorCode+" using iot_eos_v1.sensor tags("+equipmentCode+") values(now-"+time+"d,\'"+sensorCode+"\',"+value+");";
        CurlUtils.sendRestFulSql(sql);
    }

    private List<Sensor> selectChart(JSONObject jsonObject){
        String data = jsonObject.getString("data");
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
        return JSONArray.parseArray(data).stream().map(item -> {
            String test = item.toString();
            test = test.replace("[", "").replace("]", "").replace("\"", "");
            String[] split = test.split(",");
            long time = 0;
            try {
                time = simpleDateFormat.parse(split[0]).getTime();
            } catch (ParseException e) {
                e.printStackTrace();
            }
            Sensor sensor = new Sensor();
            sensor.setTs(new Timestamp(time));
            sensor.setValue(Double.valueOf(split[1]));
            return sensor;
        }).collect(Collectors.toList());
    }

    private List<Sensor> selectSensor(JSONObject jsonObject) {
        String data = jsonObject.getString("data");
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
        return JSONArray.parseArray(data).stream().map(item -> {
            String test = item.toString();
            test = test.replace("[", "").replace("]", "").replace("\"", "");
            String[] split = test.split(",");
            long time  = 0;
            try {
                time = simpleDateFormat.parse(split[0]).getTime();
            } catch (ParseException e) {
                e.printStackTrace();
            }
            Sensor sensor = new Sensor();
            sensor.setTs(new Timestamp(time));
            sensor.setSensorCode(split[1]);
            sensor.setValue(Double.valueOf(split[2]));
            sensor.setEquipmentCode(split[3]);
            return sensor;
        }).collect(Collectors.toList());
    }

    private List<ValueAvg> selectValueAvg(JSONObject jsonObject) {
        String data = jsonObject.getString("data");
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
        return JSONArray.parseArray(data).stream().map(item -> {
            String test = item.toString();
            test = test.replace("[", "");
            test = test.replace("]", "");
            test = test.replace("\"", "");
            String[] split = test.split(",");
            long time = 0;
            try {
                time = simpleDateFormat.parse(split[0]).getTime();
            } catch (ParseException e) {
                e.printStackTrace();
            }
            ValueAvg avg = new ValueAvg();
            avg.setTs(new Timestamp(time));
            avg.setValue(Double.valueOf(split[1]));
            return avg;
        }).collect(Collectors.toList());
    }
}
